CloudWatch アラームのダウンタイム(特定期間の発報抑止)を Metric Math を使用して実現してみた
コンバンハ、千葉(幸)です。
CloudWatch アラームを使用して監視・通知を実施している場合に、特定の期間だけはアラート発報を抑止したい、ということがあるかと思います。
手っ取り早く思いつくのは該当の CloudWatch アラームを一時的に無効化するパターンで、外部から CLI やプログラムを利用して定期的にステータスを変更させることでダウンタイムを実現できます。
もしくは、CloudWatch アラーム→ SNS トピックの後段に Lambda 関数を配置し、呼び出された日時が定義済みの静観期間に含まれるようであれば通知を抑止する、というパターンもあるでしょう。
いずれも CloudWatch 外部のリソースが必要となるため、もう少しお手軽に実現したいところです。最近追加された CloudWatch Metric Math 関数の中にダウンタイムの実装に使用できそうなものがあったため、その使い心地を確認してみます。
3 行まとめ
- 外部のリソースが不要な点は嬉しい
- ダウンタイムの期間の指定の仕方がちょっと……大変
- こまめに変更が必要なケースにはマッチしなさそう
使用する Metric Math 関数
ダウンタイムの実装に使用できそうな、タイムスタンプを基に戻り値を返してくれる関数は以下の通りです。
関数 | 概要 |
---|---|
MINUTE | 元の時系列の各タイムスタンプの分(UTC)を表す0から59までの整数を返す |
HOUR | 元の時系列の各タイムスタンプの時間(UTC)を表す0から23までの整数を返す |
DAY | 元の時系列の各タイムスタンプの曜日(UTC)を表す1から7までの整数のを返す。1は月曜日、7は日曜日を表す |
DATE | 元の時系列の各タイムスタンプの日(UTC)を表す1から31までの整数を返す |
MONTH | 元の時系列の各タイムスタンプの月(UTC)を表す1から12までの整数を返す |
これらの関数は IF 関数と組み合わせての使用が想定されています。
IF 関数
IF 関数は以下の書式で使用します。
IF(条件 , trueの場合の値 , falseの場合の値)
falseの場合の値
は省略できます。
また、以下の演算子を使用できます。
演算子のタイプ | サポートされている演算子 |
---|---|
比較演算子 | == , != , <= , >= , < , > |
論理演算子 | AND または && , OR または || |
以下のように()
をネストすることもできます。
IF( (条件1) OR (条件2) , trueの場合の値)
タイムスタンプを基にする関数と組み合わせる場合には、以下のように使用します。
IF(HOUR(m1) < 13 , m1)
ここでのm1
は時系列のメトリクスを表すものであり、上記の条件式は「メトリクスのタイムスタンプの時間(UTC)が 0~12 であればそのままメトリクスを返し、それ以外であれば何も返さない」という挙動になります。
IF 関数についての詳細は以下をご参照ください。
Metric Math の確認
まずは条件式の正しい書き方を確認するために、定常的に値がパブリッシュされているメトリクスを例に取ります。条件式を適用し、意図した通り特定期間のグラフの描画が変化するかを確認します。
今回は以下のメトリクスを用いて試します。
常に一定のメトリクスが発行されています。なお、ここでは JST で描画しています。
土日をダウンタイムにする場合
分かりやすく「土日(JST)は丸々ダウンタイムにしたい」というケースです。今回使用する Metrics Math 関数はいずれも UTC 基準のため、JST から変換する必要があります。
抑止したい箇所の曜日をまたいでの指定はできないため、以下を OR で繋いであげます。
- 金曜日の 15時 - 23時台(
DAY(m1)==5 AND (15<=HOUR(m1) AND HOUR(m1)<=23)
) - 土曜日(
DAY(m1)==6
) - 日曜日の 0時 - 14時台(
DAY(m1)==7 AND (0<=HOUR(m1) AND HOUR(m1)<=14)
)
実際に繋いだものが以下です。なんかこう……ワクワクしてきますね。
IF((DAY(m1)==5 AND (15<=HOUR(m1) AND HOUR(m1)<=23)) OR DAY(m1)==6 OR (DAY(m1)==7 AND (0<=HOUR(m1) AND HOUR(m1)<=14)),0,m1)
適用してみると、意図通り JST での土曜、日曜の期間はメトリクスが 0 になりました。
MINUTE を指定する場合
「日次で 10:30-20:30(JST)だけ監視対象としたい」というケースを考えます。
UTC に変換すれば 01:30-11:30 です。MINUTE での指定が必要な時間帯は時間をまたいでの指定ができないため、分割する必要があります。
以下を OR 条件でつなぎます。
- 1 時台(
HOUR(m1)==1 AND MINUTE(m1)>30
) - 2 時〜 10 時台(
2<=HOUR(m1) AND HOUR(m1)<=10
) - 11 時台(
HOUR(m1)==11 AND MINUTE(m1)<30
)
繋げたものが以下です。なんかこう……ワクワクしてきますね。
IF((HOUR(m1)==1 AND MINUTE(m1)>30) OR (2<=HOUR(m1) AND HOUR(m1)<=10) OR (HOUR(m1)==11 AND MINUTE(m1)<30) ,m1,0)
適用すると以下のようになります。
なお、falseの場合の値
を省略すればダウンタイム時の値が0
でなくnull
になります。
IF((HOUR(m1)==1 AND MINUTE(m1)>30) OR (2<=HOUR(m1) AND HOUR(m1)<=10) OR (HOUR(m1)==11 AND MINUTE(m1)<30) ,m1)
値が欠損するよりは0
を発行しておく方がよいでしょう。
ここまで見てきた曜日指定と MINUTE 指定が組み合わさると、条件式の書き方が大変なことになりそうですね、、、
CloudWatch アラームとの組み合わせ
Metric Math と CloudWatch アラームを組み合わせて、ダウンタイムに発報されないことを確認します。
今回はサンプルのメトリクスを手動で発行し、それに対してアラームをセットします。
aws cloudwatch put-metric-data\ --namespace Sample\ --metric-name TestMetric\ --value 1
このように手で叩いた時だけカウントされています。
CloudWatch アラームの作成
まずは条件式をセットします。「数式」から「空の式で始まる」を選択します。
先ほどの MINUTE を使用する例の条件式を入力します。「10:30-20:30(UTC)」以外の時間はメトリクスが 0 に上書きされます。
IF((HOUR(m1)==1 AND MINUTE(m1)>30) OR (2<=HOUR(m1) AND HOUR(m1)<=10) OR (HOUR(m1)==11 AND MINUTE(m1)<30) ,m1,0)
ベルマークのボタンを押下して CloudWatch アラームを作成します。今回は比較のため、基のメトリクスと Metric Math の計算後のグラフそれぞれで作成します。
以下の通り作成しました。1回でも 0 より大きくなった場合にアラーム状態に遷移する条件です。
↑ Metric Math をベースにしている方は0
が発行され続けているため OK 状態ですが、基のメトリクスは手動で発行しない限りデータが無い状態です。
ダウンタイム中の静観の確認
ここで再度メトリクスを発行します。発行したのは 09:40(JST)頃です。
aws cloudwatch put-metric-data\ --namespace Sample\ --metric-name TestMetric\ --value 1
基のメトリクスの方だけがアラーム状態に遷移しました。ダウンタイムの設定が正常に効いていることが分かります。
ダウンタイム外の発報の確認
CloudWatch アラーム上で以下のように数式を修正し、09:30-20:30を監視対象とするようにしてみます。
IF((HOUR(m1)==0 AND MINUTE(m1)>30) OR (1<=HOUR(m1) AND HOUR(m1)<=10) OR (HOUR(m1)==11 AND MINUTE(m1)<30) ,m1,0)
変更手順を軽く押さえておきましょう。
CloudWatch アラームの変更画面からメトリクスの「編集」を押下します。
グラフを編集できる画面に遷移するため、新たな条件式に修正し、「メトリクスの選択」を押下します。
その後、元のアラームの変更画面に戻るため、「アラームの変更」を確定させれば修正は完了です。
再度 CLI でメトリクスの発行を実行します。今回は 09:50 ごろの実行です。
aws cloudwatch put-metric-data\ --namespace Sample\ --metric-name TestMetric\ --value 1
メトリクスが記録された時間がダウンタイムに含まれていないため、どちらのアラームでもアラーム状態に遷移しました。
期待した通りの挙動です!
終わりに
Metric Math による監視抑止の仕組みを試してみました。
別に Lamnda 関数などを用意する必要がなく、CloudWatch だけで完結できるのはお手軽で嬉しいです。意図せず Lambda 関数が正常に起動しなかった、という事象も避けられるのもポイントが高いです。
一方で、ダウンタイムの指定の仕方がかなり……ワクワクする感じです。条件が細かくなるとそのぶん条件式が長くなりそうで、そこのハードルは高い印象です。そういった意味で、頻繁に時刻変更のメンテナンスが必要なケースにはマッチしないと考えました。
方式によりメリデメあるかと思いますので、選択肢の一つとして覚えておいていただければ嬉しいです。
以上、 チバユキ (@batchicchi) がお送りしました。
関連
CloudWatch アラームを一時的に無効化することで発報抑止するパターンです。